using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Timing;
using Matrix.Notification.Application.Logging;
using Matrix.Notification.Domain.Notifications;

namespace Matrix.Notification.Channels
{
    /// <summary>
    /// 推送通知通道实现
    /// </summary>
    public class PushNotificationChannel : INotificationChannel, ITransientDependency
    {
        public string ChannelType => "Push";

        private readonly ILogger<PushNotificationChannel> _logger;
        private readonly IBackgroundJobManager _backgroundJobManager;
        private readonly IClock _clock;
        private readonly IPushNotificationService _pushService;
        private readonly PushNotificationChannelOptions _options;

        public PushNotificationChannel(
            ILogger<PushNotificationChannel> logger,
            IBackgroundJobManager backgroundJobManager,
            IClock clock,
            IPushNotificationService pushService,
            IOptions<PushNotificationChannelOptions> options)
        {
            _logger = logger;
            _backgroundJobManager = backgroundJobManager;
            _clock = clock;
            _pushService = pushService;
            _options = options.Value;
        }

        public Task<bool> IsAvailableAsync(CancellationToken cancellationToken = default)
        {
            return Task.FromResult(_options.IsEnabled && _pushService.IsAvailable());
        }

        public async Task<NotificationChannelResult> SendAsync(
            object notification,
            CancellationToken cancellationToken = default)
        {
            var result = new NotificationChannelResult();

            try
            {
                var pushNotification = notification as PushNotificationMessage;
                if (pushNotification == null)
                {
                    _logger.LogError("通知对象不是推送类型");
                    return CreateFailureResult("通知对象不是推送类型");
                }

                using (var scope = _logger.LogNotificationSending(
                    pushNotification.Id,
                    NotificationChannel.Push,
                    pushNotification.DeviceTokens?.FirstOrDefault() ?? "Unknown"))
                {
                    var sendResult = await SendPushAsync(pushNotification, cancellationToken);

                    if (sendResult.Success)
                    {
                        result.IsSuccess = true;
                        result.SuccessCount = sendResult.SuccessCount;
                        result.FailureCount = sendResult.FailureCount;
                        result.MessageId = sendResult.MessageId;
                        result.SentAt = _clock.Now;

                        _logger.LogInformation(
                            "推送通知发送成功: Id={Id}, Devices={DeviceCount}, SuccessCount={SuccessCount}, " +
                            "FailureCount={FailureCount}, Duration={Duration}ms",
                            pushNotification.Id,
                            pushNotification.DeviceTokens.Count,
                            sendResult.SuccessCount,
                            sendResult.FailureCount,
                            (_clock.Now - pushNotification.CreationTime).TotalMilliseconds);
                    }
                    else
                    {
                        result.IsSuccess = false;
                        result.FailureCount = pushNotification.DeviceTokens.Count;
                        result.ErrorMessage = sendResult.ErrorMessage;

                        _logger.LogNotificationSendFailed(
                            pushNotification.Id,
                            NotificationChannel.Push,
                            sendResult.ErrorMessage ?? "Unknown error",
                            0,
                            _clock.Now - pushNotification.CreationTime);
                    }
                }

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogNotificationError(
                    ex,
                    "SendPush",
                    notification is PushNotificationMessage ? ((PushNotificationMessage)notification).Id : null);

                return CreateFailureResult(ex.Message);
            }
        }

        public async Task<NotificationChannelResult> SendBatchAsync(
            IReadOnlyCollection<object> notifications,
            CancellationToken cancellationToken = default)
        {
            var result = new NotificationChannelResult();
            var startTime = _clock.Now;
            var pushNotifications = notifications.Cast<PushNotificationMessage>().ToList();

            try
            {
                _logger.LogInformation("开始批量发送推送通知: {Count}个通知", pushNotifications.Count);

                foreach (var pushNotification in pushNotifications)
                {
                    var sendResult = await SendAsync(pushNotification, cancellationToken);

                    if (sendResult.IsSuccess)
                    {
                        result.SuccessCount += sendResult.SuccessCount;
                    }
                    else
                    {
                        result.FailureCount += sendResult.FailureCount;
                        result.ErrorMessage = sendResult.ErrorMessage;
                    }
                }

                result.IsSuccess = result.FailureCount == 0;
                result.SentAt = _clock.Now;

                var duration = _clock.Now - startTime;
                _logger.LogInformation(
                    "批量推送通知发送完成: 总通知={Total}, 成功设备={Success}, 失败设备={Failed}, 耗时={Duration}ms",
                    pushNotifications.Count,
                    result.SuccessCount,
                    result.FailureCount,
                    duration.TotalMilliseconds);

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量推送通知发送失败: {Error}", ex.Message);
                return CreateFailureResult(ex.Message);
            }
        }

        /// <summary>
        /// 发送延迟推送通知
        /// </summary>
        public async Task SendDelayedAsync(
            PushNotificationMessage pushNotification,
            TimeSpan delay,
            CancellationToken cancellationToken = default)
        {
            try
            {
                _logger.LogInformation(
                    "安排延迟推送通知发送: {DeviceCount}个设备, 延迟={Delay}分钟",
                    pushNotification.DeviceTokens.Count,
                    delay.TotalMinutes);

                await _backgroundJobManager.EnqueueAsync(
                    new DelayedPushSendJobArgs
                    {
                        PushNotification = pushNotification,
                        ScheduledTime = _clock.Now.Add(delay)
                    },
                    BackgroundJobPriority.Low,
                    cancellationToken: cancellationToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "安排延迟推送通知发送失败: {DeviceCount}个设备",
                    pushNotification.DeviceTokens.Count);
                throw;
            }
        }

        private async Task<PushSendResult> SendPushAsync(
            PushNotificationMessage pushNotification,
            CancellationToken cancellationToken = default)
        {
            try
            {
                var sendResults = new List<DeviceSendResult>();

                foreach (var deviceToken in pushNotification.DeviceTokens)
                {
                    try
                    {
                        var deviceResult = await SendToDeviceAsync(pushNotification, deviceToken, cancellationToken);
                        sendResults.Add(deviceResult);

                        if (deviceResult.Success)
                        {
                            _logger.LogDebug("推送设备发送成功: DeviceToken={DeviceToken}, MessageId={MessageId}",
                                deviceToken, deviceResult.MessageId);
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "推送设备发送异常: DeviceToken={DeviceToken}", deviceToken);
                        sendResults.Add(new DeviceSendResult
                        {
                            Success = false,
                            DeviceToken = deviceToken,
                            ErrorMessage = ex.Message
                        });
                    }
                }

                return new PushSendResult
                {
                    Success = sendResults.Any(r => r.Success),
                    SuccessCount = sendResults.Count(r => r.Success),
                    FailureCount = sendResults.Count(r => !r.Success),
                    MessageId = sendResults.FirstOrDefault(r => r.Success)?.MessageId,
                    DeviceResults = sendResults
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "发送推送通知时发生异常: {DeviceCount}",
                    pushNotification.DeviceTokens.Count);

                return new PushSendResult
                {
                    Success = false,
                    ErrorMessage = ex.Message
                };
            }
        }

        private async Task<DeviceSendResult> SendToDeviceAsync(
            PushNotificationMessage pushNotification,
            string deviceToken,
            CancellationToken cancellationToken = default)
        {
            // 检查设备令牌是否有效
            if (string.IsNullOrWhiteSpace(deviceToken) || !_pushService.IsValidDeviceToken(deviceToken))
            {
                return new DeviceSendResult
                {
                    Success = false,
                    DeviceToken = deviceToken,
                    ErrorMessage = "设备令牌无效"
                };
            }

            // 检查平台类型
            var platformType = _pushService.GetPlatformType(deviceToken);
            if (platformType == PushPlatformType.Unknown)
            {
                return new DeviceSendResult
                {
                    Success = false,
                    DeviceToken = deviceToken,
                    ErrorMessage = "不支持的推送平台"
                };
            }

            // 根据平台发送推送
            var pushPayload = CreatePushPayload(pushNotification, platformType);
            var sendResult = await _pushService.SendAsync(
                deviceToken,
                pushPayload,
                pushNotification.PlatformOptions?.GetOptions(platformType),
                cancellationToken);

            return new DeviceSendResult
            {
                Success = sendResult.Success,
                DeviceToken = deviceToken,
                MessageId = sendResult.MessageId,
                ErrorMessage = sendResult.ErrorMessage,
                StatusCode = sendResult.StatusCode
            };
        }

        private PushPayload CreatePushPayload(PushNotificationMessage pushNotification, PushPlatformType platformType)
        {
            var payload = new PushPayload
            {
                Title = pushNotification.Title,
                Message = pushNotification.Message,
                Data = pushNotification.Data,
                PlatformOptions = pushNotification.PlatformOptions
            };

            // 设置通用属性
            if (pushNotification.Badge.HasValue)
                payload.Badge = pushNotification.Badge.Value;

            if (pushNotification.Sound.HasValue)
                payload.Sound = pushNotification.Sound.Value;

            if (pushNotification.Priority.HasValue)
                payload.Priority = pushNotification.Priority.Value;

            // 设置自定义属性
            if (pushNotification.CustomProperties?.Any() == true)
            {
                foreach (var prop in pushNotification.CustomProperties)
                {
                    payload.CustomProperties[prop.Key] = prop.Value;
                }
            }

            // 根据平台设置特定属性
            switch (platformType)
            {
                case PushPlatformType.FCM:
                    SetFCMProperties(payload, pushNotification);
                    break;
                case PushPlatformType.APNs:
                    SetAPNsProperties(payload, pushNotification);
                    break;
                case PushPlatformType.HMS:
                    SetHMSProperties(payload, pushNotification);
                    break;
            }

            return payload;
        }

        private void SetFCMProperties(PushPayload payload, PushNotificationMessage pushNotification)
        {
            if (pushNotification.PlatformOptions?.FCM != null)
            {
                var fcmOptions = pushNotification.PlatformOptions.FCM;
                if (!string.IsNullOrEmpty(fcmOptions.Priority))
                    payload.Priority = fcmOptions.Priority;

                if (!string.IsNullOrEmpty(fcmOptions.TTL))
                    payload.TTL = fcmOptions.TTL;

                if (fcmOptions.CollapseKey != null)
                    payload.CollapseKey = fcmOptions.CollapseKey;

                if (fcmOptions.RetryLimit.HasValue)
                    payload.RetryLimit = fcmOptions.RetryLimit.Value;

                if (fcmOptions.DryRun.HasValue)
                    payload.DryRun = fcmOptions.DryRun.Value;
            }

            // FCM特定数据
            payload.CustomProperties["click_action"] = pushNotification.ClickAction ?? "FLUTTER_NOTIFICATION_CLICK";
            payload.CustomProperties["notification_id"] = pushNotification.Id.ToString();

            if (!string.IsNullOrEmpty(pushNotification.ImageUrl))
            {
                payload.Image = pushNotification.ImageUrl;
            }
        }

        private void SetAPNsProperties(PushPayload payload, PushNotificationMessage pushNotification)
        {
            if (pushNotification.PlatformOptions?.APNs != null)
            {
                var apnsOptions = pushNotification.PlatformOptions.APNs;
                if (!string.IsNullOrEmpty(apnsOptions.Priority))
                    payload.Priority = apnsOptions.Priority;

                if (apnsOptions.TTL.HasValue)
                    payload.TTL = apnsOptions.TTL.Value.ToString();

                if (apnsOptions.Topic != null)
                    payload.Topic = apnsOptions.Topic;

                if (apnsOptions.PushType != null)
                    payload.PushType = apnsOptions.PushType;

                if (!string.IsNullOrEmpty(apnsOptions.SubType))
                    payload.SubType = apnsOptions.SubType;

                if (apnsOptions.CollapseId != null)
                    payload.CollapseId = apnsOptions.CollapseId;
            }

            // APNs特定数据
            payload.CustomProperties["aps"] = new
            {
                alert = new
                {
                    title = pushNotification.Title,
                    body = pushNotification.Message,
                    badge = pushNotification.Badge,
                    sound = pushNotification.Sound
                },
                "notification-id" = pushNotification.Id.ToString(),
                "click-action" = pushNotification.ClickAction ?? "com.myapp.notification.click"
            };

            if (!string.IsNullOrEmpty(pushNotification.ImageUrl))
            {
                payload.CustomProperties["aps"]["image"] = pushNotification.ImageUrl;
            }
        }

        private void SetHMSProperties(PushPayload payload, PushNotificationMessage pushNotification)
        {
            if (pushNotification.PlatformOptions?.HMS != null)
            {
                var hmsOptions = pushNotification.PlatformOptions.HMS;
                if (!string.IsNullOrEmpty(hmsOptions.Priority))
                    payload.Priority = hmsOptions.Priority;

                if (hmsOptions.TTL.HasValue)
                    payload.TTL = hmsOptions.TTL.Value.ToString();

                if (hmsOptions.CollapseKey != null)
                    payload.CollapseKey = hmsOptions.CollapseKey;

                if (hmsOptions.ReceiptId != null)
                    payload.ReceiptId = hmsOptions.ReceiptId;

                if (hmsOptions.BiTag != null)
                    payload.BiTag = hmsOptions.BiTag;

                if (!string.IsNullOrEmpty(hmsOptions.Tag))
                    payload.Tag = hmsOptions.Tag;
            }

            // HMS特定数据
            payload.CustomProperties["notification_id"] = pushNotification.Id.ToString();
            payload.CustomProperties["click_action"] = pushNotification.ClickAction ?? "com.myapp.notification.click";

            if (!string.IsNullOrEmpty(pushNotification.ImageUrl))
            {
                payload.Image = pushNotification.ImageUrl;
            }
        }

        private NotificationChannelResult CreateFailureResult(string errorMessage)
        {
            return new NotificationChannelResult
            {
                IsSuccess = false,
                ErrorMessage = errorMessage,
                SuccessCount = 0,
                FailureCount = 1,
                SentAt = _clock.Now
            };
        }
    }

    /// <summary>
    /// 推送通知消息
    /// </summary>
    public class PushNotificationMessage
    {
        /// <summary>
        /// 通知ID
        /// </summary>
        public Guid Id { get; set; }

        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime CreationTime { get; set; }

        /// <summary>
        /// 设备令牌列表
        /// </summary>
        public List<string> DeviceTokens { get; set; } = new();

        /// <summary>
        /// 推送标题
        /// </summary>
        public string Title { get; set; } = string.Empty;

        /// <summary>
        /// 推送消息内容
        /// </summary>
        public string Message { get; set; } = string.Empty;

        /// <summary>
        /// 前台通知图标URL
        /// </summary>
        public string? IconUrl { get; set; }

        /// <summary>
        /// 前台通知图片URL
        /// </summary>
        public string? ImageUrl { get; set; }

        /// <summary>
        /// 点击动作
        /// </summary>
        public string? ClickAction { get; set; }

        /// <summary>
        /// 徽章数量
        /// </summary>
        public int? Badge { get; set; }

        /// <summary>
        /// 提示音
        /// </summary>
        public string? Sound { get; set; }

        /// <summary>
        /// 优先级
        /// </summary>
        public PushPriority? Priority { get; set; }

        /// <summary>
        /// 过期时间（秒）
        /// </summary>
        public int? TTL { get; set; }

        /// <summary>
        /// 自定义数据
        /// </summary>
        public Dictionary<string, object>? Data { get; set; }

        /// <summary>
        /// 自定义属性
        /// </summary>
        public Dictionary<string, object>? CustomProperties { get; set; }

        /// <summary>
        /// 平台特定配置
        /// </summary>
        public PushPlatformOptions? PlatformOptions { get; set; }
    }

    /// <summary>
    /// 推送平台选项
    /// </summary>
    public class PushPlatformOptions
    {
        /// <summary>
        /// FCM配置
        /// </summary>
        public FCMOptions? FCM { get; set; }

        /// <summary>
        /// APNs配置
        /// </summary>
        public APNsOptions? APNs { get; set; }

        /// <summary>
        /// 华为推送服务配置
        /// </summary>
        public HMSOptions? HMS { get; set; }

        /// <summary>
        /// 根据平台类型获取配置
        /// </summary>
        public object? GetOptions(PushPlatformType platformType)
        {
            return platformType switch
            {
                PushPlatformType.FCM => FCM,
                PushPlatformType.APNs => APNs,
                PushPlatformType.HMS => HMS,
                _ => null
            };
        }
    }

    /// <summary>
    /// FCM配置选项
    /// </summary>
    public class FCMOptions
    {
        /// <summary>
        /// 优先级 ("high", "normal", "low")
        /// </summary>
        public string? Priority { get; set; }

        /// <summary>
        /// 生存时间（秒）
        /// </summary>
        public string? TTL { get; set; }

        /// <summary>
        /// 折叠键（相同key的通知会被替换）
        /// </summary>
        public string? CollapseKey { get; set; }

        /// <summary>
        /// 重试次数
        /// </summary>
        public int? RetryLimit { get; set; }

        /// <summary>
        /// 测试模式（不实际发送）
        /// </summary>
        public bool? DryRun { get; set; }
    }

    /// <summary>
    /// APNs配置选项
    /// </summary>
    public class APNsOptions
    {
        /// <summary>
        /// 优先级 (10, 5, 1)
        /// </summary>
        public string? Priority { get; set; }

        /// <summary>
        /// 生存时间（秒）
        /// </summary>
        public int? TTL { get; set; }

        /// <summary>
        /// 主题（用于广播）
        /// </summary>
        public string? Topic { get; set; }

        /// <summary>
        /// 推送类型 ("alert", "background", "voip")
        /// </summary>
        public string? PushType { get; set; }

        /// <summary>
        /// 子类型
        /// </summary>
        public string? SubType { get; set; }

        /// <summary>
        /// 折叠ID
        /// </summary>
        public string? CollapseId { get; set; }
    }

    /// <summary>
    /// 华为推送服务配置选项
    /// </summary>
    public class HMSOptions
    {
        /// <summary>
        /// 优先级 ("HIGH", "NORMAL", "LOW")
        /// </summary>
        public string? Priority { get; set; }

        /// <summary>
        /// 生存时间（秒）
        /// </summary>
        public int? TTL { get; set; }

        /// <summary>
        /// 折叠键
        /// </summary>
        public string? CollapseKey { get; set; }

        /// <summary>
        /// 回执ID
        /// </summary>
        public string? ReceiptId { get; set; }

        /// <summary>
        /// 商业标签
        /// </summary>
        public string? BiTag { get; set; }

        /// <summary>
        /// 标签
        /// </summary>
        public string? Tag { get; set; }
    }

    /// <summary>
    /// 推送负载
    /// </summary>
    public class PushPayload
    {
        /// <summary>
        /// 标题
        /// </summary>
        public string Title { get; set; } = string.Empty;

        /// <summary>
        /// 消息
        /// </summary>
        public string Message { get; set; } = string.Empty;

        /// <summary>
        /// 图标
        /// </summary>
        public string? Icon { get; set; }

        /// <summary>
        /// 图片
        /// </summary>
        public string? Image { get; set; }

        /// <summary>
        /// 徽章
        /// </summary>
        public int? Badge { get; set; }

        /// <summary>
        /// 声音
        /// </summary>
        public string? Sound { get; set; }

        /// <summary>
        /// 优先级
        /// </summary>
        public PushPriority? Priority { get; set; }

        /// <summary>
        /// 生存时间
        /// </summary>
        public string? TTL { get; set; }

        /// <summary>
        /// 折叠键
        /// </summary>
        public string? CollapseKey { get; set; }

        /// <summary>
        /// 收据ID
        /// </summary>
        public string? ReceiptId { get; set; }

        /// <summary>
        /// 标签
        /// </summary>
        public string? Tag { get; set; }

        /// <summary>
        /// 主题
        /// </summary>
        public string? Topic { get; set; }

        /// <summary>
        /// 推送类型
        /// </summary>
        public string? PushType { get; set; }

        /// <summary>
        /// 子类型
        /// </summary>
        public string? SubType { get; set; }

        /// <summary>
        /// 平台选项
        /// </summary>
        public PushPlatformOptions? PlatformOptions { get; set; }

        /// <summary>
        /// 自定义数据
        /// </summary>
        public Dictionary<string, object>? Data { get; set; } = new();

        /// <summary>
        /// 自定义属性
        /// </summary>
        public Dictionary<string, object> CustomProperties { get; set; } = new();
    }

    /// <summary>
    /// 推送发送结果
    /// </summary>
    public class PushSendResult
    {
        public bool Success { get; set; }
        public int SuccessCount { get; set; }
        public int FailureCount { get; set; }
        public string? MessageId { get; set; }
        public string? ErrorMessage { get; set; }
        public List<DeviceSendResult> DeviceResults { get; set; } = new();
    }

    /// <summary>
    /// 设备发送结果
    /// </summary>
    public class DeviceSendResult
    {
        public bool Success { get; set; }
        public string DeviceToken { get; set; } = string.Empty;
        public string? MessageId { get; set; }
        public string? ErrorMessage { get; set; }
        public int? StatusCode { get; set; }
    }

    /// <summary>
    /// 延迟推送发送任务参数
    /// </summary>
    public class DelayedPushSendJobArgs
    {
        public PushNotificationMessage PushNotification { get; set; } = null!;
        public DateTime ScheduledTime { get; set; }
    }

    /// <summary>
    /// 延迟推送发送后台任务
    /// </summary>
    public class DelayedPushSendJob : AsyncBackgroundJob<DelayedPushSendJobArgs>
    {
        private readonly PushNotificationChannel _pushChannel;

        public DelayedPushSendJob(PushNotificationChannel pushChannel)
        {
            _pushChannel = pushChannel;
        }

        public override async Task ExecuteAsync(DelayedPushSendJobArgs args)
        {
            // 检查是否到了发送时间
            if (DateTime.UtcNow < args.ScheduledTime)
            {
                // 还没到时间，重新调度
                var delay = args.ScheduledTime - DateTime.UtcNow;
                await _pushChannel.SendDelayedAsync(args.PushNotification, delay);
                return;
            }

            // 发送推送
            await _pushChannel.SendAsync(args.PushNotification);
        }
    }

    /// <summary>
    /// 推送通知通道配置选项
    /// </summary>
    public class PushNotificationChannelOptions
    {
        /// <summary>
        /// 是否启用
        /// </summary>
        public bool IsEnabled { get; set; } = true;

        /// <summary>
        /// 单次推送最大设备数量
        /// </summary>
        public int MaxDevicesPerSend { get; set; } = 1000;

        /// <summary>
        /// 批量发送间隔（毫秒）
        /// </summary>
        public int BatchSendInterval { get; set; } = 100;

        /// <summary>
        /// 设备令牌缓存过期时间（分钟）
        /// </summary>
        public int DeviceTokenCacheExpiration { get; set; } = 1440; // 24小时

        /// <summary>
        /// 失败重试次数
        /// </summary>
        public int RetryCount { get; set; } = 3;

        /// <summary>
        /// 重试间隔（秒）
        /// </summary>
        public int RetryInterval { get; set; } = 300; // 5分钟

        /// <summary>
        /// 是否启用设备令牌验证
        /// </summary>
        public bool EnableDeviceTokenValidation { get; set; } = true;
    }
}